//-----------------------------------------------------------------------------
//  Copyright (C) 2005-2008 Thomas S. Ullrich 
//
//  This file is part of the Solitaire Mahjong project.
//
//  This file may be used under the terms of the GNU General Public License.
//  This project is free software; you can redistribute it and/or modify it
//  under the terms of the GNU General Public License.
//  
//  Author: Thomas S. Ullrich
//  Last update: June 1, 2007
//-----------------------------------------------------------------------------
#include <algorithm>
#include <ctime>
#include <fstream>
#include <iostream>
#include <QGraphicsScene>
#include <QApplication>
#include <QDir>
#include <QStatusBar>
#include <QMessageBox>
#include "smTileFactory.h"
#include "smDefinitions.h"
#include "smTileItem.h"
 
using namespace std;
 
smTileFactory::smTileFactory(QGraphicsScene *scene) : mScene(scene)
{
    mShadowWidth = 0;
    mShadowHeight = 0;
}
 
smTileFactory::~smTileFactory()
{
    for (unsigned int i=0; i<mTiles.size(); i++)
        if (mTiles[i]) {
            delete mTiles[i];
            mTiles[i] = 0;
        }
}
 
bool smTileFactory::makeTiles(smTileSetId tileId, smTileSize s)
{
    //
    // Load tile set. That's a directory containing
    // all tiles, each tile in normal and highlighted
    // view.
    //
     
    QString path = qApp->applicationDirPath() + "/tiles";
    QDir dir(path);
    if (!dir.exists()) {
        path = qApp->applicationDirPath() + "/../tiles";
        dir.setPath(path);
    }
#if defined(Q_OS_MAC)   
    if (!dir.exists()) {
        path = qApp->applicationDirPath() + "/../Resources/tiles";
        dir.setPath(path);
    }
#endif
    if (!dir.exists()) {
        QMessageBox::critical( 0, "Solitaire Mahjong",
                         "Cannot find the directory holding the tile sets (tiles).\n"
                         "Ceck your installation and reinstall if necessary.\n"
                         "Solitaire Mahjong will now exit.");
        exit(1);
    }
     
    //
    // Select the tile set.
    //
    path += "/";
    path += smTileSetDirectory[tileId];
    path += "/";
     
    //
    // Select the tile size.
    //
    path += smTileSetSubdirectory[s];
    path += "/";
     
    //
    // Get the width of the shadow of the tile.
    // The value is stored in a file called shadowWidth.txt
    // in the same directory as the tiles. The values can
    // be negative.
    // mShadowWidth < 0     drop shadow to the left
    // mShadowWidth > 0     drop shadow to the right
    // mShadowHeight < 0    drop shadow to the top
    // mShadowHeight > 0    drop shadow to the bottom
    //
    QString swPath = path;
    swPath += "shadowWidth.txt";
    ifstream ifs(swPath.toAscii());
    if (!ifs) {
        QMessageBox::critical( 0, "Solitaire Mahjong",
                         "Cannot open resource file 'shadowWidth.txt'. This\n"
                         "file is mandatory. Ceck your installation and \n"
                         "reinstall if necessary. Solitaire Mahjong will now exit.");
        exit(1);
    }
    ifs >> mShadowWidth >> mShadowHeight;
    ifs.close();
     
    //
    // Load all tiles.
    //
    char buf[100];
    QString filepath;
    vector<QImage*> theNormalTiles;
    vector<QImage*> theHighlightedTiles;
    QImage *imageN, *imageH;
     
    for (int i=0; i<NumberOfTiles; i++) {
        sprintf(buf,"%s_normal.png",smTileName[i]);
        filepath = path; filepath += buf;
        imageN = new QImage(filepath);
        sprintf(buf,"%s_highlighted.png",smTileName[i]);
        filepath = path; filepath += buf;
        imageH = new QImage(filepath);
        if (imageN->isNull() || imageH->isNull()) {
          QMessageBox::critical( 0, "Solitaire Mahjong",
                             "Cannot open a file holding a specific tile image.\n"
                             "Ceck your installation and reinstall if necessary.\n"
                             "Solitaire Mahjong will now exit.");
          exit(1);
        }
        theNormalTiles.push_back(imageN);
        theHighlightedTiles.push_back(imageH);
    }
     
    //
    //  Generate all tiles for the game
    //
     
    //
    // 4 of each
    //
    unsigned int k;
    for (int n=0; n<4; n++) {
        for (k=Char_1; k<=Char_9; k++) {
            mTiles.push_back(new smTileItem(mScene, theNormalTiles[k], theHighlightedTiles[k], k));
        }
        for (k=Wheel_1; k<=Wheel_9; k++) {
            mTiles.push_back(new smTileItem(mScene, theNormalTiles[k], theHighlightedTiles[k], k));
        }
        for (k=Bamboo_1; k<=Bamboo_9; k++) {
            mTiles.push_back(new smTileItem(mScene, theNormalTiles[k], theHighlightedTiles[k], k));
        }
        for (k=Wind_North; k<=Wind_West; k++) {
            mTiles.push_back(new smTileItem(mScene, theNormalTiles[k], theHighlightedTiles[k], k));
        }
        for (k=Dragon_Green; k<=Dragon_White; k++) {
            mTiles.push_back(new smTileItem(mScene, theNormalTiles[k], theHighlightedTiles[k], k));
        }
    }
    //
    // 1 of each
    //
    for (k=Season_1; k<=Season_4; k++) {
        mTiles.push_back(new smTileItem(mScene, theNormalTiles[k], theHighlightedTiles[k], k));
    }
    for (k=Flower_1; k<=Flower_4; k++) {
        mTiles.push_back(new smTileItem(mScene, theNormalTiles[k], theHighlightedTiles[k], k));
    }
     
    //
    //  Randomize vector/tiles
    //  C++ Std does not define which random generator to use
    //  in random_shuffle. In most cases (gcc) it's lrand48()
    //  where not available probably rand. To play save we 
    //  initialize both, that is except on Windows where rand48
    //  does not exist.
    //
    time_t now = time(0);
    srand((unsigned)now);
#if !defined(Q_OS_WIN32)   
    srand48((unsigned)now);
#endif
    random_shuffle(mTiles.begin(), mTiles.end());
     
    //
    //  Assign each tile the position (index) in the vector.
    //
    for (k=0; k<mTiles.size(); k++) mTiles[k]->setIndex(k);
     
    //
    //  Delete temporary images we don't need any more
    //
    for (unsigned int j=0; j<theNormalTiles.size(); j++) {
        delete theNormalTiles[j];
        delete theHighlightedTiles[j];
    }
     
    return true;
}
 
smTileItem* smTileFactory::tile(unsigned int i)
{
    if (i < mTiles.size())
        return mTiles[i];
    else
        return 0;
}
 
vector<smTileItem*>& smTileFactory::tiles()
{
    return mTiles;
}
